#include "threadpool.hpp"
#include <stdlib.h>
#include <signal.h>

#define DEFAULT_MAX_EVENT 10000    // 最大关心事件数量为10000
#define DEFAULT_LISTEN_QUEUE_NUM 5 // 默认监听队列长度为5
#define MAX_FLIE_NUM 65535         // 文件描述符最大数量
#define DEFAULT_WAIT_TIME 2000     // 默认epoll_wait阻塞事件为2000ms

//自定义信号处理方法
void addsig(int sig, sighandler_t handle)
{
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = handle;
    sigfillset(&sa.sa_mask);
    int ret = sigaction(sig, &sa, nullptr);
    if(ret == -1)
        log_message(WARNING, "Sigaction ERROR...");
}

// 作为服务器入口
int main(int argc, char *argv[])
{
    // 声明端口号
    if (argc != 2)
    {
        std::cerr << "Usage:" << std::endl;
        std::cerr << "\t" << argv[0] << " Local Port" << std::endl;
        exit(-1);
    }

    addsig(SIGPIPE, SIG_IGN);

    // 定义线程池
#ifdef TASK_ONE
    threadpool<task> tp;
#elif defined(HTTPCONN)
    threadpool<httpconn *> tp;
#endif

    // 创建数组管理每个httpconn连接
    httpconn *conns = new httpconn[DEFAULT_MAX_EVENT];

#ifdef TASK_ONE
    threadpool<task> tp;
    RandSet();
    while (true)
    {
        sleep(1);
        int a = rand() % 100;
        int b = rand() % 100;
        char op = operation[rand() % 4];
        task p_task(a, b, op);
        tp.append(p_task);
        std::cout << "分配任务:" << p_task.msg << std::endl;
    }
#elif defined(HTTPCONN)

    // 设置套接字
    int listen_sock = socket(AF_INET, SOCK_STREAM, 0);
    // 设置套接字选项
    int opt = 1;
    if (-1 == setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)))
    {
        std::cerr << errno << std::endl;
        log_message(ERROR, "Set Socket Option ERROR...");
        exit(-1);
    }
    log_message(NORMAL, "Set Socket Option Success");
    // 绑定端口号与ip入口
    struct sockaddr_in addr;
    memset(&addr, 0, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(atoi(argv[1]));
    addr.sin_addr.s_addr = INADDR_ANY;
    if (-1 == bind(listen_sock, (sockaddr *)&addr, sizeof(addr)))
    {
        std::cerr << errno << std::endl;
        log_message(WARNING, "Bind Socket ERROR...");
    }
    // 设置为监听套接字
    if (-1 == listen(listen_sock, DEFAULT_LISTEN_QUEUE_NUM))
    {
        std::cerr << errno << std::endl;
        log_message(ERROR, "Listen Socket ERROR...");
        exit(-1);
    }
    log_message(NORMAL, "Listen Socket SUCCESS");
    
    // 创建epoll文件
    int ep_fd = epoll_create(10);
    if (ep_fd == -1)
    {
        std::cerr << errno << std::endl;
        log_message(ERROR, "Epoll Create ERROR...");
        exit(-1);
    }
    log_message(NORMAL, "Epoll Create Success");

    // 设置httpconn类中的静态成员epoll_fd
    httpconn::_epoll_fd = ep_fd;

    // 将监听套接字添加进epoll事件中
    if (-1 == ADD_FD(ep_fd, listen_sock, false))
    {
        std::cerr << errno << std::endl;
        log_message(ERROR, "ADD_FD ERROR...");
        exit(-1);
    }
    log_message(NORMAL, "ADD_FD Success");

    // 获取连接
    for (;;)
    {
        struct epoll_event *events;
        // 获取事件,返回值为响应事件数量
        int event_num = epoll_wait(ep_fd, events, DEFAULT_MAX_EVENT, DEFAULT_WAIT_TIME);
        if (event_num == -1)
        {
            std::cerr << errno << std::endl;
            log_message(ERROR, "EPOLL_WAIT ERROR...");
            exit(-1);
        }
        for (int i = 0; i < event_num; i++)
        {
            int cur_fd = events[i].data.fd;
            // 若返回事件有listen_sock,需处理外来连接
            if (cur_fd == listen_sock)
            {
                struct sockaddr_in conn_addr;
                socklen_t conn_addr_len = sizeof(sockaddr_in);
                int conn_fd = accept(listen_sock, (sockaddr *)&conn_addr, &conn_addr_len);

                // 判断连接是否超载
                if (httpconn::_conn_num == MAX_FLIE_NUM)
                {
                    close(conn_fd);
                    // 响应给用户连接拥挤
                    continue;
                }

                // 将该连接添加至用户管理数组中
                conns[conn_fd].init(conn_fd, conn_addr);
                if (-1 == ADD_FD(ep_fd, conn_fd, false))
                {
                    std::cerr << errno << std::endl;
                    log_message(ERROR, "ADD_FD ERROR...");
                    // 服务器返回客户异常

                    close(conn_fd);
                    exit(-1);
                }
            }
            else if (events[i].events & EPOLLERR & EPOLLHUP & EPOLLRDHUP)
            {
                // 获取事件出错,终止连接
                DELETE_FD(ep_fd, events->data.fd);
                close(cur_fd);
            } // 由主线程读取对应fd的tcp缓冲区的数据 or 将数据写入对应fd的tcp缓冲区
            else if (events[i].events & EPOLLIN) // 正常读任务派发
            {
                // 读取数据
                tp.append(conns + cur_fd);
            }
            else if (events[i].events & EPOLLOUT)
            {
                // 写入数据
            }
        }
    }
#endif
    close(ep_fd);
    close(listen_sock);
    delete[] conns;
    return 0;
}